/*
 * MetaDataLoader.cpp
 *
 *  Created on: Nov 3, 2011
 *      Author: gassa
 */

#include "MetaDataLoader.h"
#include "../include/CUtilities.h"

bool MetaDataLoader::instanceFlag = false;
MetaDataLoader* MetaDataLoader::instance = NULL;

MetaDataLoader::MetaDataLoader() {
	instanceFlag = true;
	configInstance = config::getInstance();
	CUtilities::string_to_number(barrelNumber,
			configInstance->getValue("barrel_number"));
	setBarrelNumberToMap();
}

MetaDataLoader::~MetaDataLoader() {
	// TODO Auto-generated destructor stub
}
////////

MetaDataLoader* MetaDataLoader::getInstance() {
	if (!instanceFlag) {
		instance = new MetaDataLoader();
	}
	return instance;
}

/*
 * set the char 'a' to 'z' to the number of barrel
 */
void MetaDataLoader::setBarrelNumberToMap() {
	int barrelSpan = 26 / barrelNumber;
	int reminder = (26 % barrelNumber);
	//count for loop
	int count = 0;
	//barrel Number
	int j = 0;
	for (int i = 97; i < 123; i++) {
		barrelMapper.insert(make_pair((char) i, j));
		count++;
		if (count == barrelSpan) {
			if (reminder > 0) {
				barrelMapper.insert(make_pair((char) ++i, j));
				reminder--;
			}
			count = 0;
			j++;
		}
	}
}

/*
 * load term author into memory
 */
void MetaDataLoader::loadAuthorDict() {
	string dirPath = configInstance->getValue("path_to_dict_store_dir")
			+ "/auth_dict.txt";
	ifstream ifs;
	int count = 0;
	ifs.open(dirPath.c_str());
	if (ifs.is_open()) {
		string currLine;
		while (ifs.good()) {
			count++;
			getline(ifs, currLine);
			vector<string> temp;
			CUtilities::tokenize(currLine, temp, ":");
			if (!(temp.size() < 2)) {
				int id;
				CUtilities::string_to_number(id, temp.at(0));
				authorMapper.insert(make_pair(temp.at(1), Term(id, -1)));
			}
		}
		ifs.close();
	} else {
		cout
				<< "fail to load author dictionary, please check the config.ini file."
				<< endl;
	}
}

/*
 * load the category master into memory
 */
void MetaDataLoader::loadAuthorIndex() {
	for (int i = 0; i < barrelNumber; i++) {
		string path = configInstance->getValue("path_to_index_store_dir")
				+ "/AuthorIndex/index.inv.00" + CUtilities::number_to_string(i)
				+ ".txt";
		ifstream ifsMaster;
		ifsMaster.open(path.c_str());
		if (ifsMaster.is_open()) {
			map<size_t, size_t>* tempMap = new map<size_t, size_t>();
			string line;
			while (ifsMaster.good()) {
				getline(ifsMaster, line, '\n');
				vector<string> v;
				CUtilities::tokenize(line, v, " ");
				size_t tid;
				size_t df;
				if (v.size() == 2) {
					CUtilities::string_to_number(tid, v.at(0));
					CUtilities::string_to_number(df, v.at(1));
					tempMap->insert(make_pair(tid, df));
				}
			}
			authorToPlMapping.push_back(tempMap);
			ifsMaster.close();
		} else {
			cout << "fail to open category master file" << endl;
		}
	}
}

void MetaDataLoader::loadCategoryDict() {
	string dirPath = configInstance->getValue("path_to_dict_store_dir")
			+ "/cat_dict.txt";
	ifstream ifs;
	int count = 0;
	ifs.open(dirPath.c_str());
	if (ifs.is_open()) {
		string currLine;
		while (ifs.good()) {
			count++;
			getline(ifs, currLine);
			vector<string> temp;
			CUtilities::tokenize(currLine, temp, ":");
			if (!(temp.size() < 2)) {
				int id;
				CUtilities::string_to_number(id, temp.at(0));
				categotyMapper.insert(make_pair(temp.at(1), Term(id, -1)));
			}
		}
		ifs.close();
	} else {
		cout
				<< "fail to load category dictionary, please check the config.ini file."
				<< endl;
	}
}

/*
 * load the category master into memory
 */
void MetaDataLoader::loadCategoryIndex() {
	for (int i = 0; i < barrelNumber; i++) {
		string path = configInstance->getValue("path_to_index_store_dir")
				+ "/CategoryIndex/index.inv.00"
				+ CUtilities::number_to_string(i) + ".txt";
		ifstream ifsMaster;
		ifsMaster.open(path.c_str());
		if (ifsMaster.is_open()) {
			map<size_t, size_t>* tempMap = new map<size_t, size_t>();
			string line;
			while (ifsMaster.good()) {
				getline(ifsMaster, line, '\n');
				vector<string> v;
				CUtilities::tokenize(line, v, " ");
				size_t tid;
				size_t df;
				if (v.size() == 2) {
					CUtilities::string_to_number(tid, v.at(0));
					CUtilities::string_to_number(df, v.at(1));
					tempMap->insert(make_pair(tid, df));
				}
			}
			categoryToPlMapping.push_back(tempMap);
		} else {
			cout << "fail to open category master file" << endl;
		}
	}
}

/*
 * load the posting list for author
 */
Term* MetaDataLoader::loadAuthorPostingList(string termString) {
	//find the term in termMapper, get tid
	map<string, Term>::iterator it = authorMapper.find(termString);
	if (it == authorMapper.end()) {
		cout << "can't find match author for " << termString << endl;
		return NULL;
	}

	if (it->second.offset == -1) {
		//never load the posting for this term
		int tid = it->second.tid;
		int barrelNumber = barrelMapper[termString[0]];
		it->second.termString = termString;
		it->second.offset = 1; //the offset is flag
		it->second.plString = readPostinglistByOffset(barrelNumber, tid,
				"AuthorIndex");
		//cout << "posting list" << it->second.plString << endl;
		postingListStringToObject(it->second);
	}
	//cout << termString << "is retrieve pl complete" << endl;
	return &(it->second);
}

/*
 * load the posting list for category
 */
Term* MetaDataLoader::loadCategoryPostingList(string termString) {
	//find the term in termMapper, get tid
	map<string, Term>::iterator it = categotyMapper.find(termString);
	if (it != authorMapper.end()) {
		//never load the posting for this term
		int tid = it->second.tid;
		int barrelNumber = barrelMapper[termString[0]];
		it->second.termString = termString;
		it->second.offset = 1; //the offset is flag
		it->second.plString = readPostinglistByOffset(barrelNumber, tid,
				"CategoryIndex");
		//cout << "posting list" << it->second.plString << endl;
		postingListStringToObject(it->second);
		//cout << termString << "is retrieve pl complete" << endl;
		return &(it->second);
	} else {
		cout << "can't find match author for " << termString << endl;
		return NULL;
	}
}

/*
 * read block data from pstng file
 */
string MetaDataLoader::readPostinglistByOffset(int barrelNumber, int tid,
		string dirString) {
	string line;
	string path = configInstance->getValue("path_to_index_store_dir") + "/"
			+ dirString + "/index.inv.00"
			+ CUtilities::number_to_string(barrelNumber) + ".pstngs.txt";
	ifstream ifsPsn;
	ifsPsn.open(path.c_str());
	if (ifsPsn.is_open()) {
		map<size_t, size_t>::iterator iter;
		if (dirString == "AuthorIndex") {
			iter = authorToPlMapping.at(barrelNumber)->find(tid);
		} else if (dirString == "CategoryIndex") {
			iter = categoryToPlMapping.at(barrelNumber)->find(tid);
		} else {
			cout << "something wrong in AuthorCategory Loader";
		}

		ifsPsn.seekg(iter->second, ios::beg);
		getline(ifsPsn, line, '$');
	} else {
		cout << "fail to open file:" << path << endl;
	}
	return line;
}

/*
 *assembling the postinglist string into object list
 */
void MetaDataLoader::postingListStringToObject(Term& t) {
	vector<string> temp;
	CUtilities::tokenize(t.plString, temp, ",");
	PostingListContainer* plContainer = new PostingListContainer();
	for (int i = 0; i < temp.size(); i++) {
		CUtilities::trim_left_right(temp.at(i));
		if (temp.at(i).length() > 0) {
			vector<string> v;
			CUtilities::tokenize(temp.at(i), v, "|");
			//if( v.size() > 1 ){
			int docId;
			CUtilities::string_to_number(docId, v.at(0));
			PostingItem* pi = new PostingItem(1);
			CUtilities::string_to_number(pi->tf, v.at(1));
			plContainer->insert(make_pair(docId, pi));
			//}
		}
	}

	t.pl = plContainer;
}

